home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1997 September / Macworld (1997-09).dmg / Shareware World / Utilities / Text Processing / Alpha / Tcl / Modes / htmlElems.tcl < prev    next >
Text File  |  1997-01-21  |  31KB  |  1,126 lines

  1. #===============================================================================
  2. #    htmlElems.tcl (called by html.tcl)
  3. #
  4. #    Part of HTML mode 1.4
  5. #
  6. #    Macros for HTML elements.
  7. #
  8. #    Copyright 1996, 1997 by Johan Linde <jl@theophys.kth.se>.
  9. #    This software may be used freely, and distributed freely, as long as 
  10. #    the receiver is not obligated in any way by receiving it.
  11. #
  12. #    If you make improvements to this file, please share them!
  13. #
  14. #===============================================================================
  15.  
  16.  
  17. #
  18. # <P>
  19. #
  20.  
  21. proc htmlElemParagraph {{attr ""}} {
  22.     global HTMLmodeVars
  23.     if {$HTMLmodeVars(pIsContainer)} { 
  24.         htmlBuildCR2Elem P $attr
  25.     } else {
  26.         htmlBuildOpening P 1 1 $attr
  27.     }
  28. }
  29.  
  30.  
  31. # Insert a <BR> in the end of every line in selection.
  32.  
  33. proc htmlInsertLineBreaks {} {
  34.     if {![isSelection]} {
  35.         beep
  36.         message "No selection."
  37.         return
  38.     }
  39.     
  40.     foreach ln [split [string trimright [getSelect] "\r"] "\r"] {
  41.         append text "${ln}[htmlSetCase <BR>]\r"
  42.     }
  43.     replaceText [getPos] [selEnd] $text
  44. }
  45.  
  46. # Remove all <BR> in selection.
  47. proc htmlRemoveLineBreaks {} {
  48.     if {![isSelection]} {
  49.         beep
  50.         message "No selection."
  51.         return
  52.     }
  53.     
  54.     regsub -all "<(b|B)(r|R)(\[ \t\r\]+\[^>\]*>|>)" [getSelect] "" text
  55.     if {$text != [getSelect]} {
  56.         replaceText [getPos] [selEnd] $text
  57.     }
  58. }
  59.  
  60. # Insert <P> at empty lines in selection, and in the beginning of the selection.
  61. # Several empty lines are contracted to one.
  62. proc htmlInsertParagraphs {} {
  63.     global HTMLmodeVars
  64.     if {![isSelection]} {
  65.         beep
  66.         message "No selection."
  67.         return
  68.     }
  69.     
  70.     set pIsContainer $HTMLmodeVars(pIsContainer)
  71.     
  72.     if {[set oelem [htmlOpenElem P "" 0]] == ""} {return}
  73.     
  74.     set text "\r$oelem\r"
  75.     set prevLineEmpty 1
  76.     
  77.     foreach ln [split [string trim [getSelect] "\r"] "\r"] {
  78.         regexp {[ \t]*} $ln lntest
  79.         # Only add <P> if previous line was not empty.
  80.         if {$ln == $lntest && !$prevLineEmpty} {
  81.             set prevLineEmpty 1
  82.             if {$pIsContainer} {
  83.                 append text "[htmlCloseElem P]\r\r$oelem\r"
  84.             } else {
  85.                 append text "\r$oelem\r"
  86.             }
  87.         } else {
  88.             # Skip an empty line which follows another empty line.
  89.             if {$ln != $lntest} {
  90.                 set prevLineEmpty 0
  91.                 append text "$ln\r"
  92.             }
  93.         }
  94.     }
  95.     if {$pIsContainer} {
  96.         append text "[htmlCloseElem P]\r\r"
  97.     }
  98.     
  99.     replaceText [getPos] [selEnd] $text
  100. }
  101.  
  102.  
  103. # Ask for input how to build a list. Returns "number of items" and
  104. # "ask for list item attributes". Returns "" if canceled or any problem.
  105. proc htmlListQuestions {ltype liattr lipr} {
  106.     global HTMLmodeVars
  107.     
  108.     set promptNoisily $HTMLmodeVars(promptNoisily)
  109.     if {[string length $liattr]} {
  110.         set optatts [htmlGetOptional $liattr]
  111.         set usedatts [htmlGetUsed $liattr]
  112.         set askForMore [htmlGetAttrMore $liattr]
  113.     } else {
  114.         set optatts ""
  115.         set askForMore [htmlGetAttrMore LI]
  116.         set usedatts [htmlGetUsed LI]
  117.     }
  118.     if {$lipr != "LI"} { 
  119.         set optatts [concat $optatts [htmlGetOptional DD]]
  120.         set usedatts [concat $usedatts [htmlGetUsed DD]]
  121.         if {!$askForMore} {set askForMore [htmlGetAttrMore DD]}
  122.     }
  123.     if {$HTMLmodeVars(useBigWindows)} {
  124.         set it {0 0 3 0}
  125.         while {1} {
  126.             set txt "dialog -w 280 -h 130 -b OK 20 100 75 120 -b Cancel 110 100 165 120 \
  127.             -t {$ltype list} 100 10 250 30 \
  128.             -t {How many items?} 10 40 150 60 -e [list [lindex $it 2]] 160 40 180 55"
  129.             if {[llength $optatts]} {
  130.                 append txt " -c {Ask for attributes for each $lipr} [lindex $it 3] \
  131.                 10 70 330 85"
  132.             }
  133.             set it [eval $txt]
  134.             if {[lindex $it 1]} {return}
  135.             set items [lindex $it 2]
  136.             if {[llength $it] == 4 && [lindex $it 3]} {
  137.                 set askForLiAttr 1
  138.             } else {
  139.                 set askForLiAttr 0
  140.             }
  141.             
  142.             if {![htmlIsUnsignedInteger $items] && $ltype != "DL"} {
  143.                 alertnote "Invalid input: non-negative integer required"
  144.             } elseif {![htmlIsPositiveInteger $items] && $ltype == "DL"} {
  145.                 alertnote "Invalid input: positive integer required"
  146.             } else {
  147.                 break
  148.             }
  149.         }
  150.     } else {
  151.         if {$promptNoisily} {beep}    
  152.         while {[catch {statusPrompt "$ltype list: How many items? " htmlNumberStatusFunc} items]} {
  153.             if {$items == "Cancel all!"} {message "Cancel"; return}
  154.         }
  155.         if {![htmlIsUnsignedInteger $items] && $ltype != "DL"} {
  156.             beep; message "Invalid input: non-negative integer required."; return
  157.         } elseif {![htmlIsPositiveInteger $items] && $ltype == "DL"} {
  158.             beep; message "Invalid input: positive integer required."; return
  159.         }
  160.         if {(([llength $optatts] && $askForMore) || [llength $usedatts]) && $items} {
  161.             if {$promptNoisily} {beep}    
  162.             while {[catch {statusPrompt "Ask for attributes for each $lipr? \[n\] " \
  163.             htmlStatusAskYesOrNo} v]} {
  164.                 if {$v == "Cancel all!"} {message "Cancel"; return}
  165.             }
  166.             if {$v == "yes"} {
  167.                 set askForLiAttr 1
  168.             } else {
  169.                 set askForLiAttr 0
  170.             }
  171.         } else {
  172.             set askForLiAttr 0
  173.         }
  174.     }
  175.     return [list $items $askForLiAttr]
  176. }
  177.     
  178.  
  179. # Lists: Puts <cr>s before and after a list, inserts <li>, leaves the
  180. # insertion point there.  If anything is selected, makes it the first item.
  181. proc htmlBuildList {ltype {liattr ""} {listattr ""}} {
  182.     global HTMLmodeVars 
  183.     global htmlCurSel
  184.     global htmlIsSel
  185.     
  186.     set useTabMarks $HTMLmodeVars(useTabMarks)
  187.     set containers $HTMLmodeVars(lidtAreContainers)
  188.     
  189.     set listStr [htmlListQuestions $ltype $liattr LI]
  190.     if {![llength $listStr]} {
  191.         return
  192.     } else {
  193.         set items [lindex $listStr 0]
  194.         set askForLiAttr [lindex $listStr 1]
  195.     }
  196.  
  197.     # If zero list items, just make an htmlBuildCR2Elem
  198.     if {$items == 0} {
  199.         htmlBuildCR2Elem $ltype $listattr
  200.         return
  201.     }
  202.     
  203.     htmlGetSel
  204.     set sel $htmlCurSel
  205.     set IsSel $htmlIsSel
  206.     set text [htmlOpenCR 1]
  207.     if {$containers} {
  208.         if {[set text1 "[htmlOpenElem $ltype $listattr 0]\r"] == "\r"} {return}
  209.         append text $text1
  210.         if {$askForLiAttr} {
  211.             set text1 [htmlOpenElem LI $liattr 0]
  212.         } else {
  213.             set text1 [htmlOpenElem LI NOATTR 0]
  214.         }
  215.         if {$text1 == ""} {return}
  216.         append text $text1
  217.         if {$IsSel} {    
  218.             append text "${sel}[htmlCloseElem LI]"
  219.             set currpos [expr [getPos] + [string length $text]]
  220.         } else {
  221.             set currpos [expr [getPos] + [string length $text]]
  222.             append text [htmlCloseElem LI]
  223.         }
  224.         for {set i 1} {$i < $items} {incr i} {
  225.             append text "\r"
  226.             if {$askForLiAttr} {
  227.                 set text1 [htmlOpenElem LI $liattr 0]
  228.             } else {
  229.                 set text1 [htmlOpenElem LI NOATTR 0]
  230.             }
  231.             if {$text1 == ""} {return}
  232.             append text $text1
  233.             if {$i == 1 && $IsSel} {
  234.                 set currpos [expr [getPos] + [string length $text]]
  235.             } elseif {$useTabMarks} {
  236.                 append text "•"
  237.             }
  238.             append text [htmlCloseElem LI]
  239.         }
  240.     } else {
  241.         if {[set text1 [htmlOpenElem $ltype $listattr 0]] == ""} {return}
  242.         append text $text1
  243.         append text "\r"
  244.         if {$askForLiAttr} {
  245.             set text1 [htmlOpenElem LI $liattr 0]
  246.         } else {
  247.             set text1 [htmlOpenElem LI NOATTR 0]
  248.         }
  249.         if {$text1 == ""} {return}
  250.         append text $text1
  251.         if {$IsSel} {        
  252.             append text $sel 
  253.         } 
  254.         set currpos [expr [getPos] + [string length $text]]
  255.         for {set i 1} {$i < $items} {incr i} {
  256.             append text "\r"
  257.             if {$askForLiAttr} {
  258.                 set text1 [htmlOpenElem LI $liattr 0]
  259.             } else {
  260.                 set text1 [htmlOpenElem LI NOATTR 0]
  261.             }
  262.             if {$text1 == ""} {return}
  263.             append text $text1
  264.             if {$useTabMarks} {append text "•"}
  265.         }
  266.     }
  267.     append text "\r[htmlCloseElem $ltype]\r\r"
  268.     if {$useTabMarks} {append text "•"}
  269.     if {$IsSel} { deleteSelection }
  270.     
  271.     insertText $text
  272.     goto $currpos
  273. }
  274.  
  275.  
  276. # Add list entry.  If there is a selection, make it the entry.
  277.  
  278. proc htmlElemListEntry {liattr} {
  279.     global htmlCurSel htmlIsSel HTMLmodeVars
  280.     
  281.     set containers $HTMLmodeVars(lidtAreContainers)
  282.     set useTabMarks $HTMLmodeVars(useTabMarks)
  283.     htmlGetSel
  284.     set sel $htmlCurSel
  285.     set isSel $htmlIsSel
  286.     set text [htmlOpenCR]
  287.     if {[set text1 [htmlOpenElem LI $liattr 0]] == ""} {return}
  288.     append text $text1
  289.     if {$isSel} { deleteSelection }
  290.     if {$containers} {
  291.         if {$isSel} { 
  292.             insertText $text "${sel}" [htmlCloseElem LI]
  293.         } else {
  294.             set currpos [expr [getPos] + [string length $text]]
  295.             append text [htmlCloseElem LI]
  296.             if {$useTabMarks} { append text "•"}
  297.             insertText $text
  298.             goto $currpos
  299.         }
  300.     } else {
  301.         insertText $text $sel
  302.     }
  303. }
  304.  
  305. # Make list items from selction.
  306. proc htmlMakeList {} {
  307.     global HTMLmodeVars
  308.     
  309.     set isContainer $HTMLmodeVars(lidtAreContainers)
  310.     
  311.     if {![isSelection]} {
  312.         beep
  313.         message "No selection."
  314.         return
  315.     }
  316.     
  317.     set values [dialog -w 220 -h 130 -t "Make list" 50 10 210 30 \
  318.     -t "Each item begins with:" 10 40 160 55 -e "*" 170 40 200 55 \
  319.     -t "List:" 10 65 50 85 -m {UL UL OL DIR MENU None} 55 65 200 85 \
  320.     -b OK 20 100 85 120 -b Cancel 105 100 170 120]
  321.     
  322.     if {[lindex $values 3]} {return}
  323.     set itemStr [string trim [lindex $values 0]]
  324.     set listtype [lindex $values 1]
  325.     
  326.     if {![string length $itemStr]} {
  327.         beep
  328.         message "You must give a string which each item begins with."
  329.         return
  330.     }
  331.     set startPos [getPos]
  332.     set endPos [selEnd]
  333.     if {[catch {search -s -f 1 -i 0 -r 0 -m 0 $itemStr $startPos} res] || \
  334.     [lindex $res 1] > $endPos} {
  335.         beep 
  336.         message "No list item in selection."
  337.         return
  338.     }
  339.     # Check that the selections begins with a list item.
  340.     set preText [getText $startPos [lindex $res 0]]
  341.     if {![htmlIsWhite $preText]} {
  342.         beep
  343.         message "There is some text before the first list item."
  344.         return
  345.     }
  346.     if {$listtype != "None"} {
  347.         set text "[htmlOpenCR 1]<[htmlSetCase $listtype]>\r"
  348.     } else {
  349.         set text [htmlOpenCR]
  350.     }
  351.     # Get each list item.
  352.     set startPos [lindex $res 1]
  353.     while {![catch {search -s -f 1 -i 0 -r 0 -m 0 $itemStr $startPos} res2] && \
  354.     [lindex $res2 1] <= $endPos} {
  355.         set text2 [string trimleft [string trimright [getText $startPos [lindex $res2 0]] "\r"]]
  356.         append text "<[htmlSetCase LI]>$text2"
  357.         if {$isContainer} {append text [htmlCloseElem LI]}
  358.         append text "\r"
  359.         set startPos [lindex $res2 1]
  360.     }
  361.     set text2 [string trimleft [string trimright [getText $startPos $endPos] "\r"]]
  362.     append text "<[htmlSetCase LI]>$text2"
  363.     if {$isContainer} {append text [htmlCloseElem LI]}
  364.     append text "\r"
  365.     if {$listtype != "None"} {append text [htmlCloseElem $listtype] "\r\r"}
  366.     replaceText [getPos] [selEnd] $text
  367. }
  368.  
  369.  
  370. # Discursive Lists (term and description elems)
  371. #
  372. # The selection becomes the *description* (*not* the term)
  373.  
  374. # Build a discursive list
  375. proc htmlBuildDiscList {} {
  376.     global htmlCurSel
  377.     global htmlIsSel
  378.     global HTMLmodeVars 
  379.  
  380.     set containers $HTMLmodeVars(lidtAreContainers)
  381.     set useTabMarks    $HTMLmodeVars(useTabMarks)
  382.     
  383.     set listStr [htmlListQuestions DL DT "DT and DD"]
  384.     if {![llength $listStr]} {
  385.         return
  386.     } else {
  387.         set dlEntries [lindex $listStr 0]
  388.         set askForLiAttr [lindex $listStr 1]
  389.     }
  390.     if {$askForLiAttr} {
  391.         set liattr ""
  392.     } else {
  393.         set liattr NOATTR
  394.     }
  395.     
  396.     htmlGetSel
  397.     set Sel $htmlCurSel
  398.     set text [htmlOpenCR 1]
  399.     
  400.     if {$containers} {
  401.         if {[set text1 "[htmlOpenElem DL "" 0]\r"] == "\r"} {return}
  402.         append text $text1
  403.         # the first entry
  404.         if {[set text1 [htmlOpenElem DT $liattr 0]] == ""} {return}
  405.         append text $text1
  406.         set currpos [expr [getPos] + [string length $text]]
  407.         append text "[htmlCloseElem DT]\t"
  408.         if {[set text1 [htmlOpenElem DD $liattr 0]] == ""} {return}
  409.         append text $text1
  410.         if {$htmlIsSel} {
  411.             append text $Sel
  412.         } elseif {$useTabMarks} {
  413.             append text "•"
  414.         }
  415.         append text [htmlCloseElem DD]
  416.         # the rest of the entries
  417.         for {set i 1} {$i < $dlEntries} {incr i} {
  418.             append text "\r"
  419.             if {[set text1 [htmlOpenElem DT $liattr 0]] == ""} {return}
  420.             append text $text1
  421.             if {$useTabMarks} { append text "•" }
  422.             append text [htmlCloseElem DT] 
  423.             append text "\t"
  424.             if {[set text1 [htmlOpenElem DD $liattr 0]] == ""} {return}
  425.             append text $text1
  426.             if {$useTabMarks} { append text "•" }
  427.             append text [htmlCloseElem DD] 
  428.         }
  429.         
  430.         if {$useTabMarks} {append text "•"}
  431.         
  432.     } else {
  433.         if {[set text1 [htmlOpenElem DL "" 0]] == ""} {return}
  434.         append text $text1
  435.         append text "\r"
  436.  
  437.         # The first entry
  438.         if {[set text1 [htmlOpenElem DT $liattr 0]] == ""} {return}
  439.         append text $text1
  440.     
  441.         set currpos [expr [getPos] + [string length $text]]
  442.         append text "\t"
  443.         if {[set text1 [htmlOpenElem DD $liattr 0]] == ""} {return}
  444.         append text $text1
  445.     
  446.         if {$htmlIsSel} {
  447.             append text $Sel
  448.         }
  449.         if {$useTabMarks} {append text "•"}        
  450.     
  451.         # Now for the rest of the entries
  452.         for {set i 1} {$i < $dlEntries} {incr i} {
  453.             append text "\r"
  454.             if {[set text1 [htmlOpenElem DT $liattr 0]] == ""} {return}
  455.             append text $text1
  456.             
  457.             if {$useTabMarks} {append text "•"}
  458.             append text "\t"
  459.             if {[set text1 [htmlOpenElem DD $liattr 0]] == ""} {return}
  460.             append text $text1
  461.         
  462.             if {$useTabMarks} {append text "•"}
  463.         }
  464.     }
  465.     append text "\r[htmlCloseElem DL]\r\r"
  466.     if {$useTabMarks} {append text "•"}
  467.     if {$htmlIsSel} { deleteSelection }
  468.     insertText $text
  469.     goto $currpos
  470. }
  471.  
  472. # Add an individual entry to a discursive list
  473. proc htmlElemDiscEntry {} {
  474.     global htmlCurSel htmlIsSel
  475.     global HTMLmodeVars
  476.     set useTabMarks    $HTMLmodeVars(useTabMarks)
  477.     set containers $HTMLmodeVars(lidtAreContainers)
  478.     
  479.     htmlGetSel
  480.     set Sel $htmlCurSel
  481.     set text [htmlOpenCR]
  482.  
  483.     if {$containers} {
  484.         if {[set text1 [htmlOpenElem DT "" 0]] == ""} {return}
  485.         append text $text1
  486.         set currpos [expr [getPos] + [string length $text]]
  487.         append text "[htmlCloseElem DT]\t"
  488.         if {[set text1 [htmlOpenElem DD "" 0]] == ""} {return}
  489.         append text $text1
  490.         if {$htmlIsSel} {
  491.             append text ${Sel}
  492.         } elseif {$useTabMarks} {append text "•"}
  493.         append text [htmlCloseElem DD]
  494.         if {$useTabMarks} {append text "•"}
  495.         if {$htmlIsSel} { deleteSelection }
  496.         insertText $text [htmlCloseCR]
  497.     } else {
  498.         if {[set text1 [htmlOpenElem DT "" 0]] == ""} {return}
  499.         append text $text1
  500.         set currpos [expr [getPos] + [string length $text]]
  501.         append text "\t"
  502.         if {[set text1 [htmlOpenElem DD "" 0]] == ""} {return}
  503.         append text $text1
  504.     
  505.         if {$htmlIsSel} {
  506.             append text $Sel
  507.         }
  508.         if {$useTabMarks} {append text "•"}
  509.         if {$htmlIsSel} { deleteSelection }
  510.         insertText $text [htmlCloseCR]
  511.     }
  512.     goto $currpos
  513. }
  514.  
  515.  
  516. # Different Input fields
  517.  
  518. proc htmlBuildInputElem {inputelem {cr1 0} {cr2 1}} {
  519.     htmlBuildOpening "INPUT TYPE=\"${inputelem}\"" $cr1 $cr2 $inputelem
  520. }
  521.  
  522.  
  523. # Table template. If there is any selection it is put in the first cell.
  524. proc htmlTableTemplate {} {
  525.     global htmlCurSel htmlIsSel HTMLmodeVars
  526.     
  527.     set useTabMarks $HTMLmodeVars(useTabMarks)
  528.     
  529.     set values {"" "" 0 0 0}
  530.     set rows ""
  531.     set cols ""
  532.     set tableOpen "<[htmlSetCase TABLE]>"
  533.     set trOpen "<[htmlSetCase TR]>"
  534.     while {1} {
  535.         
  536.         set box "-t {Table template} 50 10 200 25 \
  537.         -p 50 26 150 27 \
  538.         -t {Number of rows} 10 40 150 55  -e [list [lindex $values 0]] 160 40 180 55 \
  539.         -t {Number of columns} 10 65 150 80 -e [list [lindex $values 1]] 160 65 180 80 \
  540.         -c {Table headers in first row} [lindex $values 2] 10 90 250 112 \
  541.         -c {Table headers in first column} [lindex $values 3] 10 112 250 134 \
  542.         -c {Don't insert TABLE tags} [lindex $values 4] 10 134 250 156 \
  543.         -b OK 20 250 85 270 -b Cancel 105 250 170 270\
  544.         -b {TABLE attributes} 10 170 150 190 -b {TR attributes} 10 200 150 220 "
  545.         
  546.         set values [eval [concat dialog -w 230 -h 280 $box]]
  547.         
  548.         # Cancel?
  549.         if {[lindex $values 6] } {return}
  550.         
  551.         set rows [lindex $values 0]
  552.         set cols [lindex $values 1]
  553.         set THrow [lindex $values 2]
  554.         set THcol [lindex $values 3]
  555.         set table [expr ![lindex $values 4]]
  556.         if {[lindex $values 7]} {
  557.             if {!$table} {
  558.                 alertnote "You have chosen not to insert TABLE tags."
  559.             } elseif {[set tmp [htmlChangeElement [string range $tableOpen 1 [expr [string length $tableOpen] - 2]] TABLE]] != ""} {
  560.                 set tableOpen $tmp
  561.             }
  562.             continue
  563.         }
  564.         if {[lindex $values 8]} {
  565.             if {[set tmp [htmlChangeElement [string range $trOpen 1 [expr [string length $trOpen] - 2]] TR]] != ""} {
  566.                 set trOpen $tmp
  567.             }
  568.             continue
  569.         }
  570.         
  571.         
  572.         if {![htmlIsPositiveInteger $rows] || ![htmlIsPositiveInteger $cols] } {
  573.             alertnote "The number of rows and columns must be specified."
  574.         } else {
  575.             break
  576.         }
  577.     }
  578.     
  579.     htmlGetSel
  580.     if {$htmlIsSel} {deleteSelection}
  581.     
  582.     set text [htmlOpenCR 1]
  583.     if {$table} {append text "\r" $tableOpen "\r"}
  584.     
  585.     for {set i 1} {$i <= $rows} {incr i} {
  586.         if {$i > 1 || $table} {append text "\r"}
  587.         append text "$trOpen\r"
  588.         for {set j 1} {$j <= $cols} {incr j} {
  589.             # Put TH in first row or column?
  590.             if {$i == 1 && $THrow || $j == 1 && $THcol} {
  591.                 set cell [htmlSetCase TH]
  592.             } else {
  593.                 set cell [htmlSetCase TD]
  594.             }
  595.             append text "<$cell>"
  596.             if {$i == 1 && $j == 1} {
  597.                 if {$htmlIsSel} {
  598.                     append text $htmlCurSel
  599.                 } else {
  600.                     set curPos [expr [getPos] + [string length $text]]
  601.                 }
  602.             } elseif {$htmlIsSel && ( $i == 1 && $j == 2 || $i == 2 && $cols == 1 )} {
  603.                 set curPos [expr [getPos] + [string length $text]]
  604.             } elseif {$useTabMarks} {
  605.                 append text "•"
  606.             }    
  607.             append text [htmlCloseElem $cell]
  608.         }
  609.         append text "\r[htmlCloseElem TR]\r"
  610.     }
  611.     if {$table} {append text "\r[htmlCloseElem TABLE]\r\r"}
  612.     if {$useTabMarks && ($rows > 1 || $cols > 1 || !$htmlIsSel)} {append text "•"}
  613.     insertText $text
  614.     goto $curPos
  615. }
  616.  
  617.  
  618. # Take table rows in a selection and remove the TR, TD and TH elements and
  619. # put tabs between the elements.
  620. proc htmlrowsToTabs {} {
  621.     if {![isSelection]} {
  622.         beep
  623.         message "No selection."
  624.         return
  625.     }
  626.     
  627.     set startPos [getPos]
  628.     set endPos [selEnd]
  629.     if {[catch {search -s -f 1 -i 1 -r 1 -m 0 {<TR([ \t\r]+[^>]*>|>)} $startPos} res] || \
  630.     [lindex $res 1] > $endPos} {
  631.         beep 
  632.         message "No table row in selection."
  633.         return
  634.     }
  635.     # Check that the selections begins with a table row.
  636.     set preText [getText $startPos [lindex $res 0]]
  637.     if {![htmlIsWhite $preText]} {
  638.         beep
  639.         message "First part of selection is not in a table row."
  640.         return
  641.     }
  642.     # Extract each table row.
  643.     set startPos [lindex $res 1]
  644.     while {![catch {search -s -f 1 -i 1 -r 1 -m 0 {<TR([ \t\r]+[^>]*>|>)} $startPos} res2] && \
  645.     [lindex $res2 1] <= $endPos} {
  646.         set text2 [getText $startPos [lindex $res2 0]]
  647.         regsub -all "\[\t\r\]+" $text2 " " text2
  648.         append text [string trim $text2] "\r"
  649.         set startPos [lindex $res2 1]
  650.     }
  651.     set text2 [getText $startPos $endPos]
  652.     regsub -all "\[\t\r\]+" $text2 " " text2
  653.     append text [string trim $text2]
  654.     
  655.     # Check that there is nothing after the last table row.
  656.     if {![catch {search -s -f 1 -i 1 -r 1 -m 0 {</TR>} $startPos} res] \
  657.     && [lindex $res 1] <= $endPos} {
  658.         set preText [getText [lindex $res 1] $endPos]
  659.         if {![htmlIsWhite $preText]} {
  660.             beep
  661.             message "Last part of selection not in a table row."
  662.             return
  663.         }
  664.     }
  665.     # Make the transformation.
  666.     foreach ln [split $text "\r"] {
  667.         if {![string length $ln]} continue
  668.         regsub -all {> +<} $ln "><" ln
  669.         regsub -all {<(t|T)(h|H|d|D)([ ]+[^>]*>|>)} $ln "\t" ln
  670.         regsub {    } $ln "" ln
  671.         regsub -all {</(t|T)(h|H|d|D|r|R)>} $ln "" ln
  672.         append out "$ln\r"
  673.     }
  674.     replaceText [getPos] [selEnd] $out
  675. }
  676.  
  677. # Convert tab-delimited format to table rows.
  678. # First row and first coloumn can optionally consist of table headers.
  679. proc htmltabsToRows {where} {
  680.     global HTMLmodeVars
  681.     
  682.     if {$where == "selection"} {
  683.         if {![isSelection]} {
  684.             beep
  685.             message "No selection."
  686.             return
  687.         }
  688.         set tabtext [string trim [getSelect]]
  689.         set newln "\r"
  690.         set htext "Tabs to Rows"
  691.     } else {
  692.         set fil [getfile "Select file with table."]
  693.         if {![htmlIsTextFile $fil alertnote]} {return}
  694.         set fid [open $fil r]
  695.         set tabtext [string trim [read $fid]]
  696.         close $fid
  697.         if {[regexp {\n} $tabtext]} {
  698.             set newln "\n"
  699.         } else {
  700.             set newln "\r"
  701.         }
  702.         regsub -all "\n\r" $tabtext "\n" tabtext
  703.         set htext "Import table"
  704.     }
  705.     set values {0 0 0}
  706.     set tableOpen "<[htmlSetCase TABLE]>"
  707.     set trOpen "<[htmlSetCase TR]>"
  708.     while {1} {
  709.         
  710.         set box "-t [list $htext] 50 10 200 25 \
  711.         -p 50 26 150 27 \
  712.         -c {Table headers in first row} [lindex $values 0] 10 40 250 62 \
  713.         -c {Table headers in first column} [lindex $values 1] 10 62 250 84 \
  714.         -c {Don't insert TABLE tags} [lindex $values 2] 10 84 250 106 \
  715.         -b OK 20 200 85 220 -b Cancel 105 200 170 220\
  716.         -b {TABLE attributes} 10 120 150 140 -b {TR attributes} 10 150 150 170 "
  717.         
  718.         set values [eval [concat dialog -w 230 -h 230 $box]]
  719.         
  720.         # Cancel?
  721.         if {[lindex $values 4] } {return}
  722.         
  723.         set THrow [lindex $values 0]
  724.         set THcol [lindex $values 1]
  725.         set table [expr ![lindex $values 2]]
  726.         if {[lindex $values 5]} {
  727.             if {!$table} {
  728.                 alertnote "You have chosen not to insert TABLE tags."
  729.             } elseif {[set tmp [htmlChangeElement [string range $tableOpen 1 [expr [string length $tableOpen] - 2]] TABLE]] != ""} {
  730.                 set tableOpen $tmp
  731.             }
  732.             continue
  733.         }
  734.         if {[lindex $values 6]} {
  735.             if {[set tmp [htmlChangeElement [string range $trOpen 1 [expr [string length $trOpen] - 2]] TR]] != ""} {
  736.                 set trOpen $tmp
  737.             }
  738.             continue
  739.         }
  740.         break
  741.     }
  742.             
  743.     set oelem "${trOpen}\r"
  744.     if {$oelem == "\r"} {return}
  745.     
  746.     
  747.     set out [htmlOpenCR 1]
  748.     if {$table} {append out "\r" $tableOpen "\r"}
  749.  
  750.     set i 1
  751.     foreach ln [split $tabtext $newln] {
  752.         if {![string length $ln]} {
  753.             append out "$oelem[htmlCloseElem TR]\r"
  754.         } else {
  755.             # Should there be headers in the first row?
  756.             if {$i == 1 && $THrow} {
  757.                 set cell TH
  758.             } else {
  759.                 set cell TD
  760.             }
  761.             # Should there be headers in the first column?
  762.             if {$THcol || ($i == 1 && $THrow)} {
  763.                 set fcell TH
  764.             } else {
  765.                 set fcell TD
  766.             }
  767.             regsub -all {    } $ln [htmlSetCase "</$cell><$cell>"] ln
  768.             if {$THcol} {
  769.                 regsub {[tT][dDhH]} $ln [htmlSetCase TH] ln
  770.             }
  771.             if {$i > 1 || $table} {append out "\r"}
  772.             append out "$oelem<[htmlSetCase $fcell]>$ln"
  773.             # Add cell or fcell closing, depending on if there is more than one cell.
  774.             if {![regexp [htmlCloseElem $fcell] $ln]} {
  775.                 append out [htmlCloseElem $fcell]
  776.             } else {
  777.                 append out [htmlCloseElem $cell]
  778.             }
  779.             append out "\r[htmlCloseElem TR]\r"
  780.         }
  781.         incr i
  782.     }
  783.     if {$table} {append out "\r[htmlCloseElem TABLE]\r\r"}
  784.     if {$where == "selection"} {
  785.         replaceText [getPos] [selEnd] $out
  786.     } else {
  787.         insertText $out
  788.     }
  789. }
  790.  
  791.  
  792. # Converts an NCSA or CERN image map file to a client side image map.
  793. proc htmlConvertMap {type} {
  794.     if {[catch {getfile "Select the $type image map file."} fil] || ![htmlIsTextFile $fil alertnote] ||
  795.     [catch {open $fil r} fid]} {return}
  796.     set filecont [read $fid]
  797.     close $fid
  798.     if {[regexp {\n} $filecont]} {
  799.         set newln "\n"
  800.     } else {
  801.         set newln "\r"
  802.     }
  803.     set area [html${type}map [split $filecont $newln]]
  804.     set text [lindex $area 2]
  805.     if {![string length $text]} {
  806.         alertnote "No image map found in [file tail $fil]."
  807.         return
  808.     } elseif {[lindex $area 1]} {
  809.         if {[askyesno "Some lines in [file tail $fil] have invalid syntax. They are ignored. Continue?"] == "no"} {return}
  810.     } elseif {[lindex $area 0]} {
  811.         if {[askyesno "Some lines in [file tail $fil] specify a shape not supported. They are ignored. Continue?"] == "no"} {return}
  812.     }
  813.     if {![string length [set map [htmlOpenElem MAP "" 0]]]} {return}
  814.     insertText [htmlOpenCR 1] $map "\r" $text [htmlCloseElem MAP] "\r\r"
  815. }
  816.  
  817. proc htmlNCSAmap {lines} {
  818.     set notknown 0
  819.     set someinvalid 0
  820.     set area ""
  821.     set defarea ""
  822.     foreach l $lines {
  823.         set invalid 0
  824.         set l [string trim $l]
  825.         # Skip comments and blank lines
  826.         if {[regexp {^#} $l] || ![string length $l]} {continue}
  827.         set shape [string toupper [lindex $l 0]]
  828.         if {[lsearch {RECT CIRCLE POLY DEFAULT} $shape] < 0} {
  829.             set notknown 1
  830.             continue
  831.         }
  832.         set url [lindex $l 1]
  833.         set exp "^\[0-9\]+,\[0-9\]+$"
  834.         if {[regexp $exp $url]} {
  835.             set url ""
  836.             set cind 1
  837.         } else {
  838.             set cind 2
  839.         }
  840.         switch $shape {
  841.             RECT {
  842.                 if {[regexp $exp [lindex $l $cind]] && [regexp $exp [lindex $l [expr $cind + 1]]]} {
  843.                     set coord "[lindex $l $cind],[lindex $l [expr $cind + 1]]"
  844.                 } else {
  845.                     set invalid 1
  846.                 }
  847.             }
  848.             CIRCLE {
  849.                 if {[regexp $exp [lindex $l $cind] cent] && [regexp $exp [lindex $l [expr $cind + 1]] edge]} {
  850.                     regexp {[0-9]+} $cent xc
  851.                     regexp {[0-9]+} $edge xe
  852.                     set coord "$cent,[expr $xe-$xc]"
  853.                 } else {
  854.                     set invalid 1
  855.                 }
  856.             }
  857.             POLY {
  858.                 set coord ""
  859.                 foreach c [lrange $l $cind end] {
  860.                     if {![regexp $exp $c]} {
  861.                         set invalid 1
  862.                         break
  863.                     }
  864.                     append coord "$c,"
  865.                 }
  866.                 set coord [string trimright $coord ,]
  867.             }
  868.         }
  869.         if {!$invalid} {
  870.             if {$shape == "DEFAULT"} {
  871.                 set toapp defarea
  872.             } else {
  873.                 set toapp area
  874.             }
  875.             append $toapp "<" [htmlSetCase "AREA SHAPE=\"$shape\""]
  876.             if {$shape != "DEFAULT"} {
  877.                 append $toapp " [htmlSetCase COORDS]=\"$coord\""
  878.             }
  879.             if {[string length $url]} {
  880.                 append $toapp " [htmlSetCase HREF]=\"$url\""
  881.             } else {
  882.                 append $toapp " [htmlSetCase NOHREF]"
  883.             }
  884.             append $toapp ">\r"
  885.         } else {
  886.             set someinvalid 1
  887.         }
  888.     }
  889.     append area $defarea
  890.     return [list $notknown $someinvalid $area] 
  891. }
  892.  
  893. proc htmlCERNmap {lines} {
  894.     set notknown 0
  895.     set someinvalid 0
  896.     set area ""
  897.     set defarea ""
  898.     foreach l $lines {
  899.         set invalid 0
  900.         set l [string trim $l]
  901.         # Skip comments and blank lines
  902.         if {[regexp {^#} $l] || ![string length $l]} {continue}
  903.         set shape [string toupper [lindex $l 0]]
  904.         if {![string match RECT* $shape] && ![string match CIRC* $shape] &&
  905.         ![string match POLY* $shape] && ![string match DEFAULT $shape]} {
  906.             set notknown 1
  907.             continue
  908.         }
  909.         set exp "^\\(\[0-9\]+,\[0-9\]+\\)$"
  910.         switch -glob $shape {
  911.             RECT* {
  912.                 set url [lindex $l 3]
  913.                 if {[regexp $exp [lindex $l 1]] && [regexp $exp [lindex $l 2]]} {
  914.                     set coord "[string trimleft [string trimright [lindex $l 1] )] (],[string trimleft [string trimright [lindex $l 2] )] (]"
  915.                     set shape RECT
  916.                 } else {
  917.                     set invalid 1
  918.                 }
  919.             }
  920.             CIRC* {
  921.                 set url [lindex $l 3]
  922.                 if {[regexp $exp [lindex $l 1]] && [regexp {^[0-9]+$} [lindex $l 2]]} {
  923.                     set coord "[string trimleft [string trimright [lindex $l 1] )] (],[lindex $l 2]"
  924.                     set shape CIRCLE
  925.                 } else {
  926.                     set invalid 1
  927.                 }
  928.             }
  929.             POLY* {
  930.                 set coord ""
  931.                 set url [lindex $l [expr [llength $l] - 1]]
  932.                 if {[regexp $exp $url]} {
  933.                     set url ""
  934.                     set cind 1
  935.                 } else {
  936.                     set cind 2
  937.                 }
  938.                 foreach c [lrange $l 1 [expr [llength $l] - $cind]] {
  939.                     if {![regexp $exp $c]} {
  940.                         set invalid 1
  941.                         break
  942.                     }
  943.                     append coord "[string trimleft [string trimright $c )] (],"
  944.                 }
  945.                 set coord [string trimright $coord ,]
  946.                 set shape POLY
  947.             }
  948.             DEFAULT {
  949.                 set url [lindex $l 1]
  950.             }
  951.         }
  952.         if {!$invalid} {
  953.             if {$shape == "DEFAULT"} {
  954.                 set toapp defarea
  955.             } else {
  956.                 set toapp area
  957.             }
  958.             append $toapp "<" [htmlSetCase "AREA SHAPE=\"$shape\""]
  959.             if {$shape != "DEFAULT"} {
  960.                 append $toapp " [htmlSetCase COORDS]=\"$coord\""
  961.             }
  962.             if {[string length $url]} {
  963.                 append $toapp " [htmlSetCase HREF]=\"$url\""
  964.             } else {
  965.                 append $toapp " [htmlSetCase NOHREF]"
  966.             }
  967.             append $toapp ">\r"
  968.         } else {
  969.             set someinvalid 1
  970.         }
  971.     }
  972.     append area $defarea
  973.     return [list $notknown $someinvalid $area] 
  974. }
  975.  
  976. proc htmlElemComment {} {
  977.     global htmlCurSel
  978.     global htmlIsSel
  979.     global HTMLmodeVars
  980.     set comStrs [htmlCommentStrings]
  981.     htmlGetSel
  982.     if {$htmlIsSel} { deleteSelection }
  983.     set text "[htmlOpenCR][lindex $comStrs 0]$htmlCurSel"
  984.     set currpos [expr [getPos] + [string length $text]]
  985.     append text [lindex $comStrs 1] [htmlCloseCR]
  986.     if {!$htmlIsSel && $HTMLmodeVars(useTabMarks)} {append text "•"}
  987.     insertText $text
  988.     if {!$htmlIsSel}    {
  989.         goto $currpos
  990.     }
  991. }
  992.  
  993.  
  994. #
  995. # Template for new file: HTML, TITLE, HEAD, BODY or FRAMESET
  996. # Optionally input BASE, LINK, ISINDEX, META and SCRIPT in HEAD.
  997. # We do not put in a DOCTYPE line.
  998. proc htmlNewTemplate {doctype} {
  999.     global htmlCurSel htmlIsSel HTMLmodeVars htmlHeadElements1 htmlHeadElements3 htmlPackageToUse
  1000.     set useTabMarks    $HTMLmodeVars(useTabMarks)
  1001.     set footers $HTMLmodeVars(footers)
  1002.     set headelems [set htmlHeadElements$htmlPackageToUse]
  1003.     
  1004.     set bodyText ""
  1005.     # If the window is not empty, either delete text or put it in the body.
  1006.     if {![htmlIsEmptyFile]} {
  1007.         set delBox [dialog -w 320 -h 90 -t "Nonempty window. Do you want to put the text\
  1008.         in the document's BODY, or delete it?" 10 10 310 50 \
  1009.         -b "Put in BODY" 20 60 120 80 -b Delete 140 60 205 80 -b Cancel 225 60 290 80]
  1010.         if {[lindex $delBox 1]} {
  1011.             deleteText 0 [maxPos]
  1012.         } elseif {[lindex $delBox 2]} {
  1013.             return
  1014.         } else {
  1015.             set bodyText "[getText 0 [maxPos]]\r"
  1016.         }
  1017.     } 
  1018.     
  1019.     if {$doctype == "FRAMESET"} {
  1020.         set htxt "New document with frames"
  1021.     } else {
  1022.         set htxt "New document"
  1023.     }
  1024.     # Building footer menu.
  1025.     foreach f $footers {
  1026.         lappend foot [file tail $f]
  1027.     }
  1028.     set footmenu {"No footer"}
  1029.     if {[info exists foot]} {
  1030.         set footmenu [concat $footmenu [lsort $foot]]
  1031.     }
  1032.     
  1033.     set docTitle ""
  1034.     set inHead {0 0 ""}
  1035.     foreach elem $headelems {
  1036.         lappend inHead 0
  1037.     }
  1038.     lappend inHead "No footer"
  1039.     while {![string length $docTitle]} {
  1040.         
  1041.         # Construct the dialog box.
  1042.         set box "-t [list $htxt] 100 10 300 25 -p 100 30 250 31 -t {TITLE} 10 40 60 55 \
  1043.         -e [list [lindex $inHead 2]] 70 40 390 55 \
  1044.         -t {Select the elements you want in the document\'s HEAD} 10 70 390 85"
  1045.         set hpos 100
  1046.         set wpos 10
  1047.         set i 3
  1048.         foreach elem $headelems {
  1049.             append box " -c $elem [lindex $inHead $i] $wpos $hpos [expr $wpos + 100] [expr $hpos + 15]"
  1050.             incr wpos 100
  1051.             if {$wpos > 110} {set wpos 10; incr hpos 20}
  1052.             incr i
  1053.         }
  1054.         if {$wpos > 10} {incr hpos 20}
  1055.         incr hpos 10
  1056.         append box " -t Footer 10 $hpos 80 [expr $hpos + 15] \
  1057.         -m [list [concat [list [lindex $inHead $i]] $footmenu]] 90 $hpos 250 [expr $hpos + 15]"
  1058.         incr hpos 30 
  1059.         set inHead [eval [concat dialog -w 400 -h [expr $hpos + 30] \
  1060.         -b OK 20 $hpos 85 [expr $hpos + 20] \
  1061.         -b Cancel 110 $hpos 175 [expr $hpos + 20] $box]]
  1062.         if {[lindex $inHead 1] } {
  1063.             if {[lindex $delBox 1]} {undo}
  1064.             return
  1065.         }
  1066.         set docTitle [string trim [lindex $inHead 2]]
  1067.         if {![string length $docTitle]} {
  1068.             alertnote "A document title is required."
  1069.         }
  1070.     }
  1071.     
  1072.     
  1073.     if {[set text [htmlOpenElem HTML "" 0]] == "" || 
  1074.     [set text1 [htmlOpenElem HEAD "" 0]] == "" ||
  1075.     [set text2 [htmlOpenElem TITLE "" 0]] == ""} {
  1076.         if {[lindex $delBox 1]} {undo}
  1077.         return
  1078.     }
  1079.     append text "\r\r${text1}\r\r"
  1080.     append text "${text2}${docTitle}[htmlCloseElem TITLE]\r"
  1081.     set hasScript 0
  1082.     for {set i 0} {$i < [llength  $headelems]} {incr i} {
  1083.         if {[lindex $inHead [expr $i + 3]]} {
  1084.             if {[set text1 [htmlOpenElem [lindex $headelems $i] "" 0]] != ""} {
  1085.                 append text "\r${text1}"
  1086.                 if {[lindex $headelems $i] == "SCRIPT"} {
  1087.                     append text "\r<!-- Hide content from old browsers\r"
  1088.                     set currpos [string length $text]
  1089.                     set hasScript 1
  1090.                     append text "\r// end hiding content from old browsers -->\r[htmlCloseElem SCRIPT]"
  1091.                 }
  1092.             }
  1093.         }
  1094.     }
  1095.     append text "\r\r[htmlCloseElem HEAD]\r\r"
  1096.     
  1097.     if {[set text1 [htmlOpenElem $doctype "" 0]] == ""} {
  1098.         if {[lindex $delBox 1]} {undo}
  1099.         return
  1100.     }
  1101.     append text "$text1\r\r"
  1102.     append text $bodyText
  1103.     if {!$hasScript} {
  1104.         set currpos [string length $text]
  1105.     } elseif {$useTabMarks} {
  1106.         append text "•"
  1107.     }    
  1108.     
  1109.     # Insert footer.
  1110.     set footval [lindex $inHead [expr [llength $headelems] + 3]]
  1111.     if {$footval != "No footer"} {
  1112.         set footerFile [lindex $footers [lsearch -exact $foot $footval]]
  1113.         if {![catch {readFile $footerFile} footText]} {
  1114.             append text "\r\r$footText"
  1115.         } else {
  1116.             alertnote "Could not read footer, $footerFile"
  1117.         }
  1118.     }
  1119.     append text "\r\r[htmlCloseElem $doctype]\r\r[htmlCloseElem HTML]"
  1120.     if {![htmlIsEmptyFile]} {deleteText 0 [maxPos]}
  1121.     insertText $text
  1122.  
  1123.     goto $currpos
  1124. }
  1125.